package wsi.resolve;

import org.rygh.core.face.IHasKey;
import org.rygh.semantic.model.ex.FactSet;
import org.rygh.semantic.model.ex.PredicatePath;
import org.rygh.semantic.model.rdf.Entity;
import org.rygh.semantic.model.rdf.Fact;
import org.rygh.semantic.model.rdf.Predicate;

import wsi.dataguide.tree.WSXmlLeaf;
import wsi.function.Variable;
import wsi.fusion.VariableManager;
import wsi.subgraph.tree.EntityBranch;
import wsi.subgraph.tree.EntityLeaf;

public class FactItem implements IHasKey<String> {
	private final FactSet factGroup = new FactSet();

	private VariableManager variableManager;

	private EntityBranch centerToValueBranch = null;
	private PredicatePath inputToCenterPath = null;
	private PredicatePath centerToValuePath = null;
	private Predicate tempPredicate = null;
	private WSXmlLeaf xmlLeaf = null;

	private double percentage = 0.;
	private double pcaConfidence = 0.;

	public FactItem() {

	}

	public void compose(EntityLeaf inputNode) {
		EntityLeaf node;
		Predicate pred;
		Entity epre, enext;

		final Entity in_entity = new Entity(VariableManager.E_INPUT.getValue(),
				false);
		final Variable varx = variableManager.get(xmlLeaf);

		epre = new Entity(VariableManager.E_CENTER.getValue(), false);
		enext = new Entity(varx.getValue(), true);

		if (isTemp()) {
			pred = tempPredicate;
			assert !pred.isInverse();

			factGroup.add(new Fact(epre, pred, enext));
			return;
		}

		int len = centerToValuePath.length();
		pred = centerToValuePath.getFirstPredicate();

		if (len == 1) {
			assert !pred.isInverse();
			factGroup.add(new Fact(epre, pred, enext));
		} else {
			// check if centerToValue branch crosses input node
			// we assume all literals are terminating.
			node = centerToValueBranch.getNode(1);
			if (node == inputNode)
				enext = in_entity;
			else
				enext = new Entity(variableManager.register(pred).getValue(),
						false);

			factGroup.add(new Fact(epre, pred, enext));

			for (int i = 1; i < len - 1; i++) {
				pred = centerToValuePath.getPredicate(i);

				epre = enext;
				node = centerToValueBranch.getNode(i + 1);

				if (node == inputNode)
					enext = in_entity;
				else {
					System.out
							.printf("[warn.fact_item.compose] entity var at a distant pred loc %s\n",
									pred);

					enext = new Entity(variableManager.register(pred)
							.getValue(), false);
				}

				factGroup.add(new Fact(epre, pred, enext));
			}

			pred = centerToValuePath.getLastPredicate();
			assert !pred.isInverse();

			epre = enext;
			enext = new Entity(varx.getValue(), true);

			factGroup.add(new Fact(epre, pred, enext));
		}
	}

	public PredicatePath getCenterToValulePath() {
		return centerToValuePath;
	}

	public FactSet getFactGroup() {
		return factGroup;
	}

	public PredicatePath getInputToCenterPath() {
		return inputToCenterPath;
	}

	@Override
	public String getKey() {
		// centerToValulePath==null for unmatched ones
		return String.format("I2C:%s;C2V:%s;\nXPATH:%s;",
				inputToCenterPath != null ? inputToCenterPath.getKey() : "",
				centerToValuePath != null ? centerToValuePath.getKey() : "",
				xmlLeaf.getXpath().getValue());
	}

	public double getPcaConfidence() {
		return pcaConfidence;
	}

	public double getPercentage() {
		return percentage;
	}

	public Predicate getTempPredicate() {
		return tempPredicate;
	}

	public WSXmlLeaf getXmlLeaf() {
		return xmlLeaf;
	}

	public boolean isTemp() {
		return tempPredicate != null;
	}

	public void setCenterToValueBranch(EntityBranch centerToValueBranch) {
		this.centerToValueBranch = centerToValueBranch;

		if (centerToValueBranch != null)
			centerToValuePath = this.centerToValueBranch.getPredicatePath();
	}

	public void setInputToCenterPath(PredicatePath inputToCenterPath) {
		this.inputToCenterPath = inputToCenterPath;
	}

	public void setPcaConfidence(double pcaConfidence) {
		this.pcaConfidence = pcaConfidence;
	}

	public void setPercentage(double percentage) {
		this.percentage = percentage;
	}

	public void setTempPredicate(Predicate tempPredicate) {
		this.tempPredicate = tempPredicate;
	}

	public void setVariableManager(VariableManager variableManager) {
		this.variableManager = variableManager;
	}

	public void setXmlLeaf(WSXmlLeaf xmlLeaf) {
		assert xmlLeaf != null;
		this.xmlLeaf = xmlLeaf;
	}

	@Override
	public String toString() {
		return getKey();
	}

}
